package org.dromara.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import io.seata.common.util.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.TreeBuildUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.mybatis.helper.DataBaseHelper;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.device.api.RemoteDeviceService;
import org.dromara.system.domain.SysStore;
import org.dromara.system.domain.SysUserArea;
import org.dromara.system.domain.vo.SysStoreVo;
import org.dromara.system.mapper.*;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.SysAreaBo;
import org.dromara.system.domain.vo.SysAreaVo;
import org.dromara.system.domain.SysArea;
import org.dromara.system.service.ISysAreaService;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统管理-区域配置Service业务层处理
 *
 * @author LionLi
 * @date 2024-03-15
 */
@RequiredArgsConstructor
@Service
public class SysAreaServiceImpl implements ISysAreaService {

    private final SysAreaMapper baseMapper;

    private final SysStoreMapper sysStoreMapper;

    private final SysUserMapper sysUserMapper;

    private final SysUserAreaMapper sysUserAreaMapper;


    private final SysStoreServiceImpl sysStoreServiceImpl;


    @DubboReference
    private RemoteDeviceService remoteDeviceService;

    /**
     * 查询系统管理-区域配置
     */
    @Override
    public SysAreaVo queryById(Long areaId){
        return baseMapper.selectVoById(areaId);
    }

    /**
     * 查询系统管理-区域配置列表
     */
    @Override
    public TableDataInfo<SysAreaVo> queryPageList(SysAreaBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysArea> lqw = buildQueryWrapper(bo);
        Page<SysAreaVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询系统管理-区域配置列表
     */
    @Override
    public List<SysAreaVo> queryList(SysAreaBo bo) {
        LambdaQueryWrapper<SysArea> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysArea> buildQueryWrapper(SysAreaBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysArea> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getAreaCode()), SysArea::getAreaCode, bo.getAreaCode());
        lqw.eq(bo.getParentId() != null, SysArea::getParentId, bo.getParentId());
        lqw.like(StringUtils.isNotBlank(bo.getAreaName()), SysArea::getAreaName, bo.getAreaName());
        lqw.eq(StringUtils.isNotBlank(bo.getAreaType()), SysArea::getAreaType, bo.getAreaType());
        lqw.eq(StringUtils.isNotBlank(bo.getAncestors()), SysArea::getAncestors, bo.getAncestors());
        lqw.eq(bo.getOrderNum() != null, SysArea::getOrderNum, bo.getOrderNum());
        return lqw;
    }


    @Override
    public Boolean insertByBo(SysAreaBo bo) {
        SysArea areaInfo = baseMapper.selectById(bo.getParentId());
        SysArea add = MapstructUtils.convert(bo, SysArea.class);
        add.setAreaCode(StringUtils.generateRandomString());
        add.setAncestors(areaInfo.getAncestors() + StringUtils.SEPARATOR + bo.getParentId() );
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setAreaId(add.getAreaId());
            //添加关联表
            addUserArea(bo);
        }
        return flag;
    }

    /**
     *添加用户区域
     * @param bo
     */
    private void addUserArea(SysAreaBo bo) {
        Long areaId = bo.getParentId();
        LambdaQueryWrapper<SysUserArea> wrapper  = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserArea::getAreaId,areaId);
        List<SysUserArea> sysUserAreas = sysUserAreaMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(sysUserAreas)){
            List<Long> userIds = sysUserAreas.stream().distinct().
                    map(SysUserArea::getUserId).collect(Collectors.toList());
            List<SysUserArea> userAreas = userIds.stream()
                    .map(userId -> {
                        SysUserArea sysUserArea = new SysUserArea();
                        sysUserArea.setUserId(userId);
                        sysUserArea.setAreaId(bo.getAreaId());
                        return sysUserArea;
                    })
                    .collect(Collectors.toList());
            sysUserAreaMapper.insertBatch(userAreas);
        }
    }
    /**
     * 修改系统管理-区域配置
     */
    @Override
    public Boolean updateByBo(SysAreaBo bo) {
        SysArea area = MapstructUtils.convert(bo, SysArea.class);
        SysArea oldArea = baseMapper.selectById(bo.getAreaId());
        if (!oldArea.getParentId().equals(area.getParentId())){
            SysArea newParentArea = baseMapper.selectById(area.getParentId());
            //区域父级更新,跟新下级区域的Ancestores,在跟新下级区域门店的祖籍
            if (ObjectUtil.isNotNull(newParentArea) && ObjectUtil.isNotNull(oldArea)){
               String newAncestors = newParentArea.getAncestors()+ StringUtils.SEPARATOR + newParentArea.getAreaId();
               String oldAncestors = oldArea.getAncestors();
               area.setAncestors(newAncestors);
               updateAreaChildren(area,newAncestors,oldAncestors);

            }
        }
        return baseMapper.updateById(area) > 0;
    }

    private void updateAreaChildren(SysArea sysArea, String newAncestors, String oldAncestors) {
        List<SysArea> children = baseMapper.selectList(new LambdaQueryWrapper<SysArea>()
                .apply(DataBaseHelper.findInSet(sysArea.getAreaId(), "ancestors")));
        List<SysArea> list = new ArrayList<>();
        for (SysArea child : children) {
            SysArea area = new SysArea();
            area.setAreaId(child.getAreaId());
            area.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
            list.add(area);
        }
        //修改自己的子节点
        if (CollUtil.isNotEmpty(list)) {
            if (baseMapper.updateBatchById(list)) {
                list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getAreaId()));
            }
        }
        list.add(sysArea);
        //修改门店区域下的祖籍id
        Map<Long, String>  ancestorsMap  = list.stream()
                .collect(Collectors.toMap(
                        SysArea::getAreaId,
                        SysArea::getAncestors
                ));
        List<Long> areaIds = list.stream().map(SysArea::getAreaId).collect(Collectors.toList());
        LambdaQueryWrapper<SysStore> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysStore::getGroupId,areaIds);
        List<SysStore> sysStores = sysStoreMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(sysStores)){
            sysStores.forEach(store -> {
               store.setGroupIds(ancestorsMap.get(store.getGroupId()) +StringUtils.SEPARATOR+ store.getGroupId());
            });
            sysStoreMapper.updateBatchById(sysStores);
        }
    }


    /**
     * 批量删除系统管理-区域配置
     */
    @Override
    public Boolean deleteWithValidById(Long areaId) {
        return baseMapper.deleteById(areaId) > 0;
    }

    /**
     * 判断是否存在下级区域
     *
     * @param areaId
     * @return
     */
    @Override
    public boolean hasChildByAreaId(Long areaId) {
        return baseMapper.exists(new LambdaQueryWrapper<SysArea>()
                .eq(SysArea::getParentId, areaId));
    }

    @Override
    public List<Tree<Long>> tree(SysAreaBo bo) {
        bo.setUserId(LoginHelper.getUserId());
        List<SysAreaVo> sysAreaVos = sysUserMapper.selectUserAreaListByUser(bo.getUserId());
        List<SysStoreVo> sysStoreVos = sysUserMapper.selectUserStoreListByUser(bo);
        if (CollectionUtils.isEmpty(sysAreaVos)&& CollectionUtils.isEmpty(sysStoreVos)){
          return List.of();
        }
        List<SysStoreVo> noAreaStores ;
        if (CollectionUtils.isNotEmpty(sysAreaVos)){
            List<Long> areaIds = sysAreaVos.stream().map(SysAreaVo::getAreaId).toList();
            //不在区域下门店
            noAreaStores = sysStoreVos.stream().filter(sysStoreVo -> !areaIds.contains(sysStoreVo.getGroupId()))
                    .collect(Collectors.toList());
            //在区域下门店
            List<SysStoreVo> areaStores = sysStoreVos.stream().filter(sysStoreVo -> areaIds.contains(sysStoreVo.getGroupId()))
                    .collect(Collectors.toList());
            List<SysStoreVo> deviceInfoByStoreIds = sysStoreServiceImpl.buildDeviceInfoByStoreIds(areaStores, bo.getIsDevice());
            Map<Long, List<SysStoreVo>> storeMap =
                    deviceInfoByStoreIds.stream()
                            .collect(Collectors.groupingBy(SysStoreVo::getGroupId));

            sysAreaVos.forEach(sysArea -> {
                sysArea.setStores(storeMap.get(sysArea.getAreaId()));
            });
        }else {
            noAreaStores = sysStoreVos;
        }
        if (CollectionUtils.isNotEmpty(noAreaStores)){
            List<SysStoreVo> deviceInfoByStoreIds = sysStoreServiceImpl.buildDeviceInfoByStoreIds(noAreaStores, bo.getIsDevice());
            SysAreaVo sysAreaVo = new SysAreaVo();
            sysAreaVo.setAreaId(1L);
            sysAreaVo.setAreaName("未分配区域的门店");
            if (!sysAreaVos.isEmpty()){
                SysAreaVo sysArea = sysAreaVos.get(0);
                sysAreaVo.setParentId (sysArea.getParentId());
            }else {
                sysAreaVo.setParentId(0L);
            }
            sysAreaVo.setAncestors("0");
            sysAreaVo.setOrderNum(0L);
            sysAreaVo.setStores(deviceInfoByStoreIds);
            sysAreaVos.add(sysAreaVo);
        }
        return buildAreaTreeSelect(sysAreaVos);
    }
    /**
     * 构建前端所需要下拉树结构
     *
     * @param areas 区域列表
     * @return 下拉树结构列表
     */
    @Override
    public List<Tree<Long>> buildAreaTreeSelect(List<SysAreaVo> areas) {
        //先组装sysAreaVO,在对sysAreaVo进行递归改成树结构
        return TreeBuildUtils.build(areas, (area, node) -> {
            node.setId(area.getAreaId());
            node.setParentId(area.getParentId());
            node.setWeight(area.getOrderNum());	//排序权重
            node.setName(area.getAreaName());
            // 如果不想一个个putExtra，可以直接Bean 转 Map 遍历赋值
            Map<String, Object> map = BeanUtil.beanToMap(area);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                node.putExtra(entry.getKey() ,entry.getValue());
            }

        });

    }

    /**
     * 存在门店
     *
     * @param areaId
     * @return
     */
    @Override
    public boolean hasStoreByAreaId(long areaId) {
        //只要有门店就不能删除
        return sysStoreMapper.exists(new LambdaQueryWrapper<SysStore>()
                .eq(SysStore::getGroupId, areaId));
    }
}
